package com.maggie.demo.scgsentinel.config;

import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.maggie.demo.scgsentinel.handler.GatewayBlockExceptionHandler;
import com.maggie.demo.scgsentinel.handler.SentinelBlockRequestHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.handler.FilteringWebHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.result.view.ViewResolver;

import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.List;

@Order(1)
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class GatewayConfiguration implements ApplicationContextAware {
    
    @Autowired
    protected FilteringWebHandler filteringWebHandler;
    
    @Value("${spring.application.name}")
    private String PJ_NAME;
    
    public String getPJ_NAME() {
        return PJ_NAME;
    }
    
    public void setPJ_NAME(String PJ_NAME) {
        this.PJ_NAME = PJ_NAME;
    }
    
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;
    private final BlockRequestHandler blockRequestHandler;
    private ApplicationContext applicationContext;
    
    
    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
        this.blockRequestHandler = new SentinelBlockRequestHandler();
    }
    
    // 不配置异常处理,采用默认的提示
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new GatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }
    
    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
    
    
    @PostConstruct
    public void doInit() throws Exception {
        
        initBlockStrategy();
        
    }
    
    private void initBlockStrategy() {
        String[] beanNamesForType = applicationContext.getBeanNamesForType(BlockRequestHandler.class);
        if (beanNamesForType != null && beanNamesForType.length > 0) {
            GatewayCallbackManager.setBlockHandler(applicationContext.getBean(beanNamesForType[0], BlockRequestHandler.class));
        } else {
            GatewayCallbackManager.setBlockHandler(blockRequestHandler);
        }
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    
    /**
     * @Description 加这个注解可以直接通过注册中心的name直接调用服务
     * @Date 2021/8/12 14:28
     **/
    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
}
